#!/usr/bin/perl

package DBClause;

sub new { bless { data => [] }, shift; }

sub data {
	my $self= shift;
	return $self->{data} unless @_;
	return '' unless @{$self->{data}};
	return $_[0] . join($_[1],@{$self->{data}});
}

sub add {
	my $self=shift;
	push @{ $self->{data} }, @_;
}

sub reset { $_[0]->{data}=[]; $_[0]; }

package DBSet;
our @ISA = ( qw/DBClause/ );

sub new {
	bless { data => [] }, shift;
}

sub add {
	my $self=shift;

	my %data= @{ $self->data }; 
	my %new_data= ( @_ );

	my @result=();
	my @data= @{ $self->data }; 
	my @new_data=();

	while(@data) {
		my $k=shift @data;
		my $v=shift @data;
		if (!defined $new_data{ $k }) {
			push @result, $k, $v;
		}
	}

	$self->reset;
	$self->SUPER::add( @result, @_ );
}

sub data {
	my $self= shift;
	return $self->{data} unless @_;
	return '' unless @{$self->{data}};

	my @data= @{ $self->data };
	my $str=$_[0];

	while(@data) {
		$str.=shift(@data);
		$str.='=' . shift(@data);
		$str.=$_[1] if @data;
	}

	$str;
}

# проверка что поле уже установлено
sub is_set {
	my $self=shift;
	my %h= @{ $self->data };
	defined $h{ $_[0] }
}

package DBQuery;

our $VERSION = 0.1;

my %_command_sub = (
	'select' => \&_select,
	'insert' => \&_insert_values,
	'delete' => \&_delete,
	'update' => \&_update,
);

# $table %args
sub new {
	my $class=shift;
	my $table=shift;
	my %args=@_;
	my $self= bless {
		%args,
		map { $_ => DBClause->new } qw/what tables where group order limit/,
	}, $class;

	$self->{set}=new DBSet;
	$self->table($table);
	$self->tables($table);
}

sub type { $_[0]->{type} }

sub get {
	my($self, $cmd)=@_;
	( $_command_sub{$cmd} )->($self);
}

sub reset {
	my $self=shift;
	map { $self->$_->reset } ( @_ ? @_ : qw/what where set tables group order limit/ );
	$self->tables( $self->table ) unless @{ $self->tables->data };
	$self;
}

sub _select {
	my $self=shift;
	'SELECT '
		. ( $self->type eq 'firebird' ? $self->limit->data("\n\tFIRST ", ' SKIP ') : '' )
		. $self->what->data("\n\t", ', ')
		. $self->tables->data("\n\tFROM ", ', ')
		. $self->where->data("\n\tWHERE ", ' AND ')
		. $self->group->data("\n\tGROUP BY ", ', ')
		. $self->order->data("\n\tORDER BY ", ', ')
		. ( $self->type eq 'mysql' ? $self->limit->data("\n\tLIMIT ", ', ') : '' )
}

sub _update {
	my $self=shift;
	'UPDATE ' . $self->table
		. $self->set->data("\n\tSET\n\t\t", ",\n\t\t")
		. $self->where->data("\n\tWHERE\n\t\t", ' AND ')
		. $self->order->data("\n\tORDER BY ", ', ')
}

sub _insert {
	my $self=shift;
	'INSERT INTO ' . $self->table
		. $self->set->data("\n\tSET\n\t\t", ",\n\t\t")
}

sub _delete {
	my $self=shift;
	'DELETE FROM ' . $self->table
		. $self->where->data("\n\tWHERE\n\t\t", ' AND ')
}

sub _insert_values {
	my $self=shift;
	my %set=@{ $self->set->data };
	'INSERT INTO ' . $self->table . " (" . join(', ', keys %set)
		. ")\n\tVALUES (" . join(', ', values %set) . ")"
		. ( $self->type eq 'firebird' and $self->{id_name} ? "\n\tRETURNING " . $self->{id_name} : '' )
}

sub table {
	my $self=shift;
	$self->{_table}=shift if @_;
	$self->{_table};
}

sub tables {
	my $self=shift;
	return $self->{tables} unless @_;
	$self->{tables}->add(@_);
	$self;
}

sub set {
	my $self=shift;
	return $self->{set} unless @_;
	$self->{set}->add(@_);
	$self;
}

sub what  {
	my $self=shift;
	return $self->{what} unless @_;
	$self->{what}->add(@_);
	$self;
}

sub where  {
	my $self=shift;
	return $self->{where } unless @_;
	$self->{where }->add(@_);
	$self;
}

sub group  {
	my $self=shift;
	return $self->{group } unless @_;
	$self->{group }->add(@_);
	$self;
}

sub order  {
	my $self=shift;
	return $self->{order } unless @_;
	$self->{order }->add(@_);
	$self;
}

sub  limit {
	my $self=shift;
	return $self->{ limit} unless @_;
	$self->{ limit}->add(@_);
	$self;
}

1;
